// ------------------------------------------------------------------------------------------
// Licensed by Interprise Solutions.
// http://www.InterpriseSolutions.com
// For details on this license please visit  the product homepage at the URL above.
// THE ABOVE NOTICE MUST REMAIN INTACT.
// ------------------------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Web;
using Interprise.Framework.Customer.DatasetGateway;
using InterpriseSuiteEcommerceCommon.DataAccess;
using InterpriseSuiteEcommerceCommon.DTO;
using InterpriseSuiteEcommerceCommon.Extensions;
using InterpriseSuiteEcommerceCommon.Tool;

namespace InterpriseSuiteEcommerceCommon
{
    /// <summary>
    /// Summary description for ShoppingCart.
    /// </summary>
    ///
    public enum CartTypeEnum
    {
        ShoppingCart = 0,
        WishCart = 1,
        RecurringCart = 2,
        GiftRegistryCart = 3
    }

    public enum CouponTypeEnum
    {
        OrderCoupon = 0,
        ProductCoupon = 1
    }

    public enum CouponDiscountTypeEnum
    {
        PercentDiscount = 0,
        AmountDiscount = 1
    }

    public enum DateIntervalTypeEnum
    {
        Unknown = 0,
        Daily = 1,
        Weekly = 2,
        Monthly = 3,
        Yearly = 4
    }

    public enum VatDefaultSetting
    {
        Inclusive = 1,
        Exclusive = 2
    }

    public class CartItem : IComparable, IClonable
    {
        public Customer ThisCustomer = Customer.Current;
        public DateTime m_CreatedOn = DateTime.MinValue;        
        public int m_ShoppingCartRecordID = 0;
        public CartTypeEnum m_CartType = CartTypeEnum.ShoppingCart;        
        public string _customerCode = string.Empty;
        public decimal m_Quantity;
        public decimal m_AllocatedQty;
        public decimal m_MinimumQuantity;
        public string m_TextOption;
        public decimal Weight;
        
        private decimal _price = decimal.Zero;
        private decimal _taxRate = decimal.Zero;

        private bool _priceAndTaxAlreadyComputed = false;        

        
        //added by m.d
        public int CompareTo(Object item)
        {
            if (item is CartItem)
            {
                var citem = item as CartItem;
                return this.ItemCode.CompareTo(citem.ItemCode);
            }
            else
                throw new ArgumentException("Object is not a CartItem");
        }

        public enum CartComparableArgs
        {
            ITEM_CODE,
            ITEM_NAME,
            ITEM_DESCRIPTION,
            SUPPLIER_CODE,
            PRICE,
            ITEM_SUPPLIER_CODE,
            ITEM_SUPPLIER_NAME,
            DEFAULT
        }

        public int CompareTo(Object item, CartComparableArgs args)
        {
            if (item is CartItem)
            {
                CartItem citem = (CartItem)item;
                switch (args)
                {
                    case CartComparableArgs.ITEM_NAME:
                        return ItemName.CompareTo(citem.ItemName);
                    case CartComparableArgs.ITEM_DESCRIPTION:
                        return ItemDescription.CompareTo(citem.ItemDescription);
                    case CartComparableArgs.SUPPLIER_CODE:
                        return SupplierCode.CompareTo(citem.SupplierCode);
                    case CartComparableArgs.PRICE:
                        return Price.CompareTo(citem.Price);
                    case CartComparableArgs.ITEM_SUPPLIER_CODE:
                        return ItemSupplierCode.CompareTo(citem.ItemSupplierCode);
                    case CartComparableArgs.ITEM_SUPPLIER_NAME:
                        return ItemSupplierName.CompareTo(citem.ItemSupplierName);
                    default:
                        return ItemCode.CompareTo(citem.ItemCode);
                }
            }
            else
                throw new ArgumentException("Object is not a CartItem");

        }

        public class CartItemComparer : System.Collections.Generic.IComparer<CartItem>
        {

            private CartItem.CartComparableArgs compArg;

            public CartItemComparer(CartItem.CartComparableArgs arg)
            {
                compArg = arg;
            }

            int System.Collections.Generic.IComparer<CartItem>.Compare(CartItem itm1, CartItem itm2)
            {
                return itm1.CompareTo(itm2, compArg);
            }
        }
       
        public decimal Price
        {
            get 
            {
                if (!_priceAndTaxAlreadyComputed)
                {
                    // NOTE:
                    // Retrieving the price is expensive to do in IS
                    // We'll just get it by demand
                    ComputePriceAndTax();
                }

                return _price; 
            }
        }

        public void SetPrice(decimal price)
        {
            _price = price;
            _priceAndTaxAlreadyComputed = true;
        }
        
        public decimal TaxRate
        {
            get 
            {
                if (!_priceAndTaxAlreadyComputed)
                {
                    // NOTE:
                    // Retrieving the price is expensive to do in IS
                    // We'll just get it by demand
                    ComputePriceAndTax();
                }

                return _taxRate;
            }
        }

        private void ComputePriceAndTax()
        {
            decimal price = decimal.Zero;
            decimal vat = decimal.Zero;

            switch (this.ItemType)
            {
                case Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT:
                    KitComposition kitCartComposition = KitComposition.FromCart(ThisCustomer,
                                                            this.m_CartType, 
                                                            this.ItemCode, 
                                                            this.Id);

                    kitCartComposition.Quantity = Convert.ToDecimal(this.m_Quantity * this.UnitMeasureQty);
                    kitCartComposition.UnitMeasureCode = this.UnitMeasureCode;

                    _price      = kitCartComposition.GetSalesPrice(ref vat);
                    _taxRate    = vat;
                    break;
                default:
                    bool withVat =  AppLogic.AppConfigBool("VAT.Enabled") && 
                                    ThisCustomer.VATSettingReconciled == VatDefaultSetting.Inclusive;

                    string itemCode = this.ItemCode;
                    if (this.ItemType == "Matrix Item")
                    {
                        itemCode = AppLogic.GetItemCode(this.ItemCode);
                    }

                    decimal promotionalPrice = decimal.Zero;

                    price = InterpriseHelper.GetSalesPriceAndTax(ThisCustomer.CustomerCode, 
                                itemCode, 
                                ThisCustomer.CurrencyCode, 
                                Convert.ToDecimal(this.m_Quantity),
                                this.UnitMeasureCode,
                                withVat,
                                ref promotionalPrice,
                                ref vat, new UnitMeasureInfo { Code = string.Empty }, ThisCustomer);

                    if (promotionalPrice != decimal.Zero)
                    {
                        price = promotionalPrice;
                    }

                    _price = price;
                    _taxRate = vat;
                    break;
            }

            _priceAndTaxAlreadyComputed = true;
        }

        public decimal UnitPrice
        {
            get
            {
                decimal price = decimal.Zero;
                decimal vat = decimal.Zero;

                switch (this.ItemType)
                {
                    case Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT:
                        KitComposition kitCartComposition = KitComposition.FromCart(ThisCustomer,
                                                                this.m_CartType,
                                                                this.ItemCode,
                                                                this.Id);

                        kitCartComposition.Quantity = decimal.One;
                        kitCartComposition.UnitMeasureCode = this.UnitMeasureCode;
                        price = kitCartComposition.GetSalesPrice(ref vat);
                        break;
                    default:
                        bool withVat = AppLogic.AppConfigBool("VAT.Enabled") &&
                                        ThisCustomer.VATSettingReconciled == VatDefaultSetting.Inclusive;

                        decimal promotionalPrice = decimal.Zero;
                        price = InterpriseHelper.GetSalesPriceAndTax(ThisCustomer.CustomerCode,
                                    this.ItemCode,
                                    ThisCustomer.CurrencyCode,
                                    decimal.One,
                                    this.UnitMeasureCode,
                                    withVat,
                                    ref promotionalPrice,
                                    ref vat);

                        if (promotionalPrice != decimal.Zero)
                        {
                            price = promotionalPrice;
                        }
                        break;
                }

                return price;
            }            
        }


        public string m_ShippingAddressCounter;
        public string m_ShippingAddressID;
        public string m_ShippingMethodID;
        public string m_ShippingMethod;
        public Address m_ShippingDetail;
        public string m_Notes;
        public string ItemCode;
        public int ItemCounter;
        public int CBNItemID;
        public string ItemName;
        public string ItemDescription;
        public string Status;
        public Guid Id;
        public string ItemType;
        public string UnitMeasureCode;
        public decimal UnitMeasureQty;
        public List<decimal> RestrictedQuantities = new List<decimal>();
        public decimal InStock;
        public decimal FreeStock;
        public string KitPricingType;
        public string SupplierCode;
        public string ItemSupplierCode;
        public string ItemSupplierName;
        public bool IsDropShip;
        public bool IsCheckoutOption;
        public bool IsPrePacked;
        public bool IsOverSized;
        public bool IsCBN;
        public string OverSizedShippingMethodCode;

        public int MoveableQuantity;

        public bool HasSupplier
        {
            get { return !CommonLogic.IsStringNullOrEmpty(SupplierCode); }
        }

        public bool CanShipSeparately
        {
            get { return (this.IsPrePacked || this.IsOverSized) && !this.IsDownload && !this.IsService; }
        }

        public string DisplayName
        {
            get
            {
                if (string.IsNullOrEmpty(ItemDescription))
                {
                    return ItemName;
                }

                return ItemDescription;
            }
        }

        public bool IsOverFreeStockCount
        {
            get { return m_Quantity > FreeStock; }
        }

        public bool IsOutOfStock
        {
            get { return FreeStock <= 0; }
        }

        public bool IsDownload
        {
            get { return this.ItemType == Interprise.Framework.Base.Shared.Const.ITEM_TYPE_ELECTRONIC_DOWNLOAD; }
        }

        public bool IsService
        {
            get { return this.ItemType == Interprise.Framework.Base.Shared.Const.ITEM_TYPE_SERVICE; }
        }

        public bool IsAKit
        {
            get { return this.ItemType == Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT; }
        }

        public Guid? GiftRegistryID { get; set; }
        public Guid? RegistryItemCode { get; set; }

        public string Dimensions;        

        public SalesOrderDatasetGateway.CustomerSalesOrderDetailViewRow AssociatedLineItemRow = null;

        public CartItem Copy()
        {
            // Copy all the value types as is
            // but the leave special case for some reference types...
            var newCopy = new CartItem();
            newCopy.m_CreatedOn = this.m_CreatedOn;
            newCopy.m_ShoppingCartRecordID = this.m_ShoppingCartRecordID;
            newCopy.m_CartType = this.m_CartType;
            newCopy._customerCode = this._customerCode;
            newCopy.m_Quantity = this.m_Quantity;
            newCopy.m_TextOption = this.m_TextOption;
            newCopy.Weight = this.Weight;
            newCopy.m_ShippingAddressCounter = this.m_ShippingAddressCounter;
            newCopy.m_ShippingAddressID = this.m_ShippingAddressID;
            newCopy.m_ShippingMethodID = this.m_ShippingMethodID;
            newCopy.m_ShippingMethod = this.m_ShippingMethod;
            newCopy.m_ShippingDetail = this.m_ShippingDetail;
            newCopy.m_Notes = this.m_Notes;
            newCopy.ItemCode = this.ItemCode;
            newCopy.ItemCounter = this.ItemCounter;
            newCopy.ItemName = this.ItemName;
            newCopy.ItemDescription = this.ItemDescription;
            newCopy.Id = this.Id;
            newCopy.ItemType = this.ItemType;
            newCopy.UnitMeasureCode = this.UnitMeasureCode;
            newCopy.UnitMeasureQty = this.UnitMeasureQty;
            newCopy.Status = this.Status;
            List<int> copyOfRestrictedQuantities = new List<int>();
            foreach (int quantity in this.RestrictedQuantities.ToArray())
            {
                newCopy.RestrictedQuantities.Add(quantity);
            }
            newCopy.InStock = this.InStock;
            newCopy.FreeStock = this.FreeStock;

            newCopy.AssociatedLineItemRow = this.AssociatedLineItemRow;
            newCopy.KitPricingType = this.KitPricingType;
            newCopy.SupplierCode = this.SupplierCode;

            newCopy.IsOverSized = this.IsOverSized;
            newCopy.IsPrePacked = this.IsPrePacked;
            newCopy.Dimensions = this.Dimensions;
            newCopy.OverSizedShippingMethodCode = this.OverSizedShippingMethodCode;
            return newCopy;
        }

        public void IncrementQuantity(decimal quantity)
        {
            quantity = CommonLogic.RoundQuantity(quantity);
            DB.ExecuteSQL("UPDATE EcommerceShoppingCart SET Quantity = " + CommonLogic.IIF(this.RestrictedQuantities.Count == 0, "Quantity+{0}", "{0}") + " WHERE ShoppingCartRecID = {1}", quantity, this.m_ShoppingCartRecordID);
        }

        public void SetQuantity(decimal quantity)
        {
            quantity = CommonLogic.RoundQuantity(quantity);
            if (quantity > 0)
            {
                DB.ExecuteSQL("UPDATE EcommerceShoppingCart SET Quantity = {0} WHERE ShoppingCartRecID = {1}", quantity, this.m_ShoppingCartRecordID);
                this.m_Quantity = quantity;
            }
            else
            {
                if(this.ItemType == Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT)
                {
                    DB.ExecuteSQL("DELETE wkc FROM EcommerceKitCart wkc WHERE wkc.CartID = '{0}'", this.Id.ToString());
                }

                DB.ExecuteSQL("DELETE wc FROM EcommerceShoppingCart wc WHERE wc.ShoppingCartRecGuid = '{0}'", this.Id.ToString());
            }
        }

        public bool Matches(string itemCode, string addressCode, int itemCounter, string unitMeasureCode)
        {
            return Matches(itemCode, addressCode, itemCounter, unitMeasureCode, null);
        }

        public bool Matches(string itemCode, string addressCode, int itemCounter, string unitMeasureCode, KitComposition composition)
        {
            if (this.ItemCode == itemCode &&
                this.ItemCounter == itemCounter &&
                this.m_ShippingAddressID == addressCode &&                
                this.UnitMeasureCode == unitMeasureCode)
            {
                if (this.ItemType == Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT &&
                    composition != null)
                {
                    KitComposition thisComposition = GetKitComposition();
                    if (null != thisComposition)
                    {
                        return thisComposition.Matches(composition);
                    }
                }
                else
                {
                    return true;
                }
            }

            return false;
        }

        public KitComposition GetKitComposition()
        {
            if (this.ItemType == Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT)
            {
                KitComposition cartItemKitComposition = KitComposition.FromCart(ThisCustomer, this.m_CartType, this.ItemCode, this.Id);
                return cartItemKitComposition;
            }

            return null;
        }

        public class ReserveItemCollection : List<ReserveItem>
        {
        }

        public T Clone<T>()
        {
            return (T)this.MemberwiseClone();
        }

        public decimal? RegistryItemQuantity
        {
            get 
            {
                if (!RegistryItemCode.HasValue) return null;
                return GiftRegistryDA.GetGiftRegistryItemQuantityByRegistryItemCode(RegistryItemCode.Value);
            }
        }

        /// <summary>
        /// test if the cart quantity is greater the Remaining registry item quantity
        /// </summary>
        /// <returns>Boolean</returns>
        public bool HasRegistryItemQuantityConflict()
        {
            return ((RegistryItemQuantity.HasValue) && (this.m_Quantity > RegistryItemQuantity));
        }

        public bool IsRegistryStillExist()
        {
            if (!GiftRegistryID.HasValue) return false;
            return GiftRegistryDA.IsRegistryExist(GiftRegistryID.Value);
        }
    }

    public class ReserveItem
    {
        private decimal _qtyReserved = decimal.Zero;
        private DateTime _shipDate = DateTime.Now;
        private string _itemCode = string.Empty;


        public decimal QtyReserved
        {
            get { return _qtyReserved; }
            set { _qtyReserved = value; }
        }

        public DateTime ShipDate
        {
            get { return _shipDate.Date; }
            set { _shipDate = value; }
        }

        public string ItemCode
        {
            get { return _itemCode; }
            set { _itemCode = value; }
        }
    }

    public struct CouponStruct
    {
        public string m_Code;
        public CouponTypeEnum m_CouponType;
        public string m_Description;
        public DateTime m_ExpirationStartDate;
        public DateTime m_ExpirationDate;
        public CouponDiscountTypeEnum m_DiscountType;
        public Decimal m_DiscountAmount;
        public Decimal m_DiscountPercent;
        public bool m_IncludesFreeShipping;
        public bool m_IncludesAllCustomer;
        public bool m_IncludesAllProduct;
        public bool m_ExpiresOnFirstUseByAnyCustomer;
        public bool m_ExpiresAfterOneUsageByEachCustomer;
        public int m_ExpiresAfterNUses;
        public Decimal m_RequiresMinimumOrderAmount;
        public string m_ValidForThisEntity;
        public int m_NumUses;
    }

    public struct AddressInfo
    {
        public string m_NickName;
        public string m_FirstName;
        public string m_LastName;
        public string m_Company;
        public ResidenceTypes m_ResidenceType;
        public string m_Address1;
        public string m_Address2;
        public string m_Suite;
        public string m_City;
        public string m_State;
        public string m_Zip;
        public string m_Country;
        public string m_Phone;
        public string m_EMail;
    }

    public class CartItemCollection : List<CartItem>
    {
    }

    public class ShoppingCart
    {
        #region Private Variables
        private int m_SkinID;
        protected CartTypeEnum m_CartType;
        protected Customer m_ThisCustomer;        
        private CouponStruct m_Coupon;        
        private string m_EMail;        
        protected CartItemCollection m_CartItems = new CartItemCollection();
        private System.Collections.Generic.Dictionary<string, EntityHelper> m_EntityHelpers;
        private string m_DeleteString;
        private string m_OrderNotes;
        private bool m_InventoryTrimmed;
        private bool m_HasNoStockPhasedOutItem;
        private bool m_MinimumQuantitiesUpdated;
        private bool m_OnlyLoadRecurringItemsThatAreDue;
        private string m_OriginalRecurringOrderNumber = string.Empty;
        private Addresses m_CustAddresses = new Addresses();

        // WARNING THESE VALUES ARE ONLY FOR CACHING PERFORMANCE REASONS, they are set after first call in the object, and presumed
        // good for the life of "one" page:
        private Hashtable m_CachedTotals = new Hashtable();

        private decimal m_FreeShippingThreshold = 0.0M;
        private decimal m_MoreNeededToReachFreeShipping = 0.0M;
        private bool m_ShippingIsFree = false;
        private bool m_CouponsAllowed = false;
        
        #endregion

        protected ShoppingCart() {}
        public ShoppingCart(int SkinID, Customer ThisCustomer, CartTypeEnum CartType, string OriginalRecurringOrderNumber, bool OnlyLoadRecurringItemsThatAreDue)
            : this(null, SkinID, ThisCustomer, CartType, OriginalRecurringOrderNumber, OnlyLoadRecurringItemsThatAreDue,true)
        { }

        public ShoppingCart(System.Collections.Generic.Dictionary<string, EntityHelper> EntityHelpers, int SkinID, Customer ThisCustomer, CartTypeEnum CartType, string OriginalRecurringOrderNumber, bool OnlyLoadRecurringItemsThatAreDue, bool LoadDatafromDB, string pagename = "")
        {
            
            m_EntityHelpers = EntityHelpers;
            m_SkinID = SkinID;
            m_ThisCustomer = ThisCustomer;
            m_CartType = CartType;
            m_OriginalRecurringOrderNumber = OriginalRecurringOrderNumber;
            m_OnlyLoadRecurringItemsThatAreDue = OnlyLoadRecurringItemsThatAreDue;
            m_DeleteString = AppLogic.GetString("shoppingcart.cs.31", m_SkinID, m_ThisCustomer.LocaleSetting, true);

            if (m_DeleteString.Length == 0)
            {
                m_DeleteString = "Delete";
            }

            if (!AppLogic.AppConfigBool("DisallowCoupons"))
            {
                m_CouponsAllowed = true;
            }

            if (LoadDatafromDB)
            {
                //deadlock
                int nooftries = 0;
                while (nooftries < AppLogic.InterpriseExceptionFacadeNumberOfTries)
                {
                    try
                    {
                        LoadFromDB(CartType);
                        break;
                    }
                    catch (SqlException ex)
                    {
                        if (ex.ErrorCode == 1205)
                        {
                            nooftries += 1;
                            m_CartItems.Clear();
                        }
                        else
                        {
                            throw;
                        }
                    }
                }

                if (!m_CouponsAllowed)
                {
                    string customerCode = CommonLogic.IIF(ThisCustomer.IsRegistered, ThisCustomer.CustomerCode, ThisCustomer.CustomerID);
                    if (ThisCustomer.IsRegistered)
                    {
                        DB.ExecuteSQL("UPDATE Customer SET CouponCode=NULL WHERE CustomerCode=" + DB.SQuote(customerCode));
                    }
                    else
                    {
                        DB.ExecuteSQL("UPDATE EcommerceCustomer SET CouponCode=NULL WHERE CustomerID=" + DB.SQuote(customerCode));
                    }  
                }
            }
        }

        public decimal TotalQuantity()
        {
            decimal sum = 0;
            foreach (CartItem c in m_CartItems)
            {
                sum += c.m_Quantity;
            }
            return sum;
        }
       
        public virtual bool MeetsMinimumOrderQuantity(Decimal MinOrderQuantity)
        {
            if (MinOrderQuantity <= 0 || IsEmpty())
            {
                return true; // disable checking for empty cart or all system products cart (those are handled separately)
            }
            decimal N = 0;
            foreach (CartItem c in this.CartItems)
            {
                if (!c.IsService)
                {
                    N += c.m_Quantity;
                }
            }
            return (N >= MinOrderQuantity);
        }

        public void Age(int NumDays, CartTypeEnum CartType)
        {
            if (NumDays > 0)
            {
                ShoppingCart.Age(m_ThisCustomer.CustomerCode, NumDays, CartType);
                LoadFromDB(CartType);
            }
        }

        public static void Age(string CustomerID, int NumDays, CartTypeEnum CartType)
        {
            if (NumDays > 0 && CustomerID.Length != 0)
            {
                // remember, you can't "age" the recurring cart:
                if (CustomerID.Length != 0 && CartType != CartTypeEnum.RecurringCart)
                {
                    string AgeDate = Localization.ToDBDateTimeString(System.DateTime.Now.AddDays(-NumDays));
                    DB.ExecuteSQL("delete from EcommerceShoppingCart where WebSiteCode = " + DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode) + " and CartType=" + ((int)CartType).ToString() + " and customerCode=" + DB.SQuote(CustomerID.ToString()) + " and CreatedOn<" + DB.DateQuote(AgeDate));
                    DB.ExecuteSQL("delete from EcommerceKitCart where CartId not in (select ShoppingCartRecGUID from EcommerceShoppingCart with (NOLOCK) where WebSiteCode = " + DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode) + " and CartType=" + ((int)CartType).ToString() + " and customerCode=" + DB.SQuote(CustomerID.ToString()) + ") and customerCode=" + DB.SQuote(CustomerID.ToString()) + " and CreatedOn<" + DB.DateQuote(AgeDate));
                }
                // now clear out any "deleted" products:
                // NOTE: we are also cleaning out "recurring" items that are deleted
                DB.ExecuteSQL("delete from EcommerceShoppingCart where WebSiteCode = " + DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode) + " and productid not in (select A.Counter as productid from InventoryItem A with (NOLOCK) INNER JOIN InventoryItemWebOption B with (NOLOCK) ON A.ItemCode = B.ItemCode WHERE B.published=1)" +
                              " and customerCode=" + DB.SQuote(CustomerID.ToString()));
                DB.ExecuteSQL("delete from EcommerceKitCart where CartId not in (select ShoppingCartRecGUID from EcommerceShoppingCart with (NOLOCK) where WebSiteCode = " + DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode) + " and customerCode=" + DB.SQuote(CustomerID.ToString()) + ") and ItemCode not in (select A.ItemCode from InventoryItem A with (NOLOCK) INNER JOIN InventoryItemWebOption B with (NOLOCK) ON A.ItemCode = B.ItemCode WHERE B.published=1)" +
                              " and customerCode=" + DB.SQuote(CustomerID.ToString()));
                DB.ExecuteSQL("delete from EcommerceKitCart where CartId not in (select ShoppingCartRecGUID from EcommerceShoppingCart with (NOLOCK) where WebSiteCode = " + DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode) + " and customerCode=" + DB.SQuote(CustomerID.ToString()) + ") and ItemKitCode not in (select A.ItemCode as ItemKitCode from InventoryItem A with (NOLOCK) INNER JOIN InventoryItemWebOption B with (NOLOCK) ON A.ItemCode = B.ItemCode WHERE B.published=1)" +
                              " and customerCode=" + DB.SQuote(CustomerID.ToString()));
            }
        }

        public bool IsEmpty(string CustomerID, CartTypeEnum CartType, string ContactCode)
        {
            return (NumItems(CustomerID, CartType, ContactCode) == 0);
        }

        public static bool CartIsEmpty(string customerCode, CartTypeEnum CartType)
        {
            return DB.GetSqlN("select count(*) as N from EcommerceShoppingCart  with (NOLOCK) where CartType=" + ((int)CartType).ToString() + " and WebSiteCode = " + DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode) + " and CustomerCode=" + DB.SQuote(customerCode)) == 0;
        }

        public static decimal NumItems(string CustomerID, CartTypeEnum CartType, string ContactCode)
        {
            decimal N = 0;
            if (CustomerID.Length != 0)
            {
                using (var con = DB.NewSqlConnection())
                {
                    con.Open();
                    using (var rs = DB.GetRSFormat(con, "select sum(quantity) as NumItems from EcommerceShoppingCart  with (NOLOCK) where CartType=" + ((int)CartType).ToString() + " and WebSiteCode = " + DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode) + " and CustomerCode=" + DB.SQuote(CustomerID.ToString()) + " and ContactCode=" + DB.SQuote(ContactCode.ToString())))
                    {
                        rs.Read();
                        N = DB.RSFieldDecimal(rs, "NumItems");
                    }
                }
            }
            return N;
        }

        private decimal GetKitItemPrice(CartItem item)
        {
            decimal price = decimal.Zero;

            bool isCurrencyIncludedForInventorySelling = InterpriseHelper.IsCurrencyIncludedForInventorySelling(ThisCustomer.CurrencyCode);

            // Special case 2 
            //  Currency is added in Inventory Selling Currency late
            //  after the kit has been created, ideally the kit should regenerate kit pricing for this currency
            //  but for the meantime, we should handle this by looking into the home currency
            bool currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem =
            InterpriseHelper.CurrencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYet(ThisCustomer.CurrencyCode, item.ItemCode);

            string kitDetailQuery =
                string.Format(
                    "exec EcommerceGetWebKitCartDetail @ItemKitCode = {0}, @CurrencyCode = {1}, @LanguageCode = {2}, @CustomerCode = {3}, @CartID = {4}, @ContactCode = {5}",
                    DB.SQuote(item.ItemCode),
                    DB.SQuote(CommonLogic.IIF((isCurrencyIncludedForInventorySelling && !currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem), ThisCustomer.CurrencyCode, Currency.GetHomeCurrency())), 
                    DB.SQuote(ThisCustomer.LocaleSetting),
                    DB.SQuote(ThisCustomer.CustomerCode),
                    DB.SQuote(item.Id.ToString()),
                    DB.SQuote(ThisCustomer.ContactCode)
                );

            // The exchange rate to be used if we must convert
            decimal exchangeRate = decimal.Zero;
            if (!isCurrencyIncludedForInventorySelling || 
                currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem)
            {
                exchangeRate = Currency.GetExchangeRate(ThisCustomer.CurrencyCode);
            }

            // read the records from the EcommerceKitCart table...

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, kitDetailQuery))
                {
                    while (reader.Read())
                    {
                        decimal total = decimal.Zero;
                        if (isCurrencyIncludedForInventorySelling &&
                            !currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem)
                        {
                            total = DB.RSFieldDecimal(reader, "TotalRate");
                        }
                        else
                        {
                            total = Interprise.Facade.Base.SimpleFacade.Instance.ConvertCurrency(exchangeRate, DB.RSFieldDecimal(reader, "TotalRate"), false, ThisCustomer.CurrencyCode, Interprise.Framework.Base.Shared.Enum.CurrencyFormat.Total);
                        }

                        price += total;
                    }
                }
            }

            return price;
        }

        private Guid? GiftRegistryID { get; set; }
        private Guid? GiftRegistryItemCode { get; set; }

        private bool HasNoStockPhasedOutComponent(string itemcode, string itemid)
        {
            bool hasNoStockPhasedOutComp = false;
            bool isCurrencyIncludedForInventorySelling = InterpriseHelper.IsCurrencyIncludedForInventorySelling(ThisCustomer.CurrencyCode);
            bool currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem =
            InterpriseHelper.CurrencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYet(ThisCustomer.CurrencyCode, itemcode);

            string kitDetailQuery =
                string.Format(
                    "exec EcommerceGetWebKitCartDetail @ItemKitCode = {0}, @CurrencyCode = {1}, @LanguageCode = {2}, @CustomerCode = {3}, @CartID = {4}, @ContactCode = {5}",
                    DB.SQuote(itemcode),
                    DB.SQuote(CommonLogic.IIF((isCurrencyIncludedForInventorySelling && !currencyIsIncludedInInventorySellingCurrencyButHasNoKitPricingDetailYetForThisItem), ThisCustomer.CurrencyCode, Currency.GetHomeCurrency())),
                    DB.SQuote(ThisCustomer.LocaleSetting),
                    DB.SQuote(ThisCustomer.CustomerCode),
                    DB.SQuote(itemid),
                    DB.SQuote(ThisCustomer.ContactCode));

            using (SqlConnection con = DB.NewSqlConnection())
            {
                con.Open();
                using (IDataReader reader = DB.GetRSFormat(con, kitDetailQuery))
                {
                    while (reader.Read())
                    {
                        string status = DB.RSField(reader, "Status");
                        decimal freeStock = Convert.ToDecimal(DB.RSFieldDecimal(reader, "FreeStock"));
                 
                        if (status == "P" && freeStock <= 0)
                        {
                            hasNoStockPhasedOutComp = true;
                        }
                    }
                }
            }

            return hasNoStockPhasedOutComp;
        }

        protected void LoadFromDB(CartTypeEnum CartType)
        {
            m_InventoryTrimmed = false;
            m_MinimumQuantitiesUpdated = false;
            m_HasNoStockPhasedOutItem = false;
            bool shouldLimitCartToQuantityOnHand = AppLogic.AppConfigBool("Inventory.LimitCartToQuantityOnHand");
            bool isTrimmed = false;

            if (CartType == CartTypeEnum.ShoppingCart && m_ThisCustomer.CustomerCode.Length != 0)
            {
                // only do these on the shopping cart
                m_InventoryTrimmed = InterpriseHelper.CheckCartInventoryIfTrimmed(m_ThisCustomer, shouldLimitCartToQuantityOnHand);
                //Checking for Minimum Order Quantity of Item(s) will be temporarily deferred.
                // Concerning issue : Multiple Uom Items
                if (ThisCustomer.PrimaryShippingAddressID != string.Empty)
                {
                    // repair addresses if required
                    // force all "0" or "invalid" address id records in the cart to be set to the primary shipping address. This is to avoid total confusion
                    // later in the cart where gift registry items, multi-ship items, etc, are all involved!
                    string msql = "UPDATE EcommerceShoppingCart SET " +
                        " ShippingAddressID=" + DB.SQuote(ThisCustomer.PrimaryShippingAddressID) +
                        " WHERE CartType=" + ((int)CartTypeEnum.ShoppingCart).ToString() +
                        " AND CustomerCode=" + DB.SQuote(ThisCustomer.CustomerCode) +
                        " AND ContactCode=" + DB.SQuote(ThisCustomer.ContactCode) +
                        " AND ShippingAddressID NOT IN (SELECT ShiptoCode FROM CustomerShipTo with (NOLOCK) WHERE CustomerCode=" + DB.SQuote(m_ThisCustomer.CustomerCode) +
                        " UNION ALL " +
                        " SELECT CreditCardCode AS ShiptoCode FROM CustomerCreditcard with (NOLOCK) WHERE CustomerCode=" + DB.SQuote(m_ThisCustomer.DefaultBillingCode) + ")" +
                        " AND ShippingAddressID NOT IN (SELECT cs.shiptocode FROM EcommerceGiftRegistry egr " +
                                                        "INNER JOIN CRMcontact cc on egr.contactguid = cc.contactguid " +
                                                        "INNER JOIN Customer c on cc.entitycode = c.customercode " +
                                                        "INNER JOIN customershipto cs on c.customercode = cs.customercode)";

                    DB.ExecuteSQL(msql);
                }
            }

            // Need to pull the Shipping Address from Address table
            var sql = new StringBuilder(4096);
            sql.AppendFormat(
                "dbo.GetEcommerceShoppingCart {0}, {1}, {2}, {3}, {4}, {5}", 
                ((int)CartType).ToString(), 
                DB.SQuote(m_ThisCustomer.CustomerCode.ToString()),
                DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode),
                DB.SQuote(ThisCustomer.WarehouseCode),
                DB.SQuote(ThisCustomer.LanguageCode),
                DB.SQuote(ThisCustomer.ContactCode)
            );
            sql = sql.Replace("^", " with (NOLOCK) ");

            m_CartItems.Clear();
            int i = 0;

            bool couponSet = false;

            m_EMail = string.Empty;
            m_OrderNotes = string.Empty;

            using (var con = DB.NewSqlConnection())
            {
                con.Open();
                using (var rs = DB.GetRSFormat(con, sql.ToString()))
                {
                    while (rs.Read())
                    {
                        var newItem = new CartItem();
                        newItem.m_CreatedOn = DB.RSFieldDateTime(rs, "CreatedOn");
                        newItem.m_ShoppingCartRecordID = DB.RSFieldInt(rs, "ShoppingCartRecID");
                        newItem.Id = (Guid)rs["ShoppingCartRecGUID"];
                        newItem.m_CartType = (CartTypeEnum)DB.RSFieldInt(rs, "CartType");
                        newItem.ItemCounter = DB.RSFieldInt(rs, "ItemCounter");
                        newItem._customerCode = m_ThisCustomer.CustomerCode.ToString();
                        newItem.m_Quantity = DB.RSFieldDecimal(rs, "Quantity");
                        newItem.m_TextOption = DB.RSField(rs, "TextOption");
                        newItem.m_ShippingMethodID = DB.RSFieldInt(rs, "ShippingMethodID").ToString();
                        newItem.m_ShippingMethod = DB.RSFieldByLocale(rs, "ShippingMethod", m_ThisCustomer.LocaleSetting);
                        newItem.UnitMeasureCode = DB.RSField(rs, "UnitMeasureCode");
                        newItem.UnitMeasureQty = DB.RSFieldDecimal(rs, "UnitMeasureQty");
                        newItem.ItemDescription = DB.RSField(rs, "ItemDescription");                        
                        newItem.Dimensions = DB.RSField(rs,"ProductDimensions");                        
                        newItem.IsPrePacked = DB.RSFieldBool(rs, "IsPrePacked");
                        newItem.IsOverSized = DB.RSFieldBool(rs, "IsOverSized");
                        newItem.OverSizedShippingMethodCode = DB.RSField(rs, "OverSizedShippingMethodCode");
                        newItem.m_AllocatedQty = DB.RSFieldDecimal(rs, "AllocatedQty");
                        newItem.GiftRegistryID = DB.RSFieldGUID3(rs, "GiftRegistryID");
                        newItem.RegistryItemCode = DB.RSFieldGUID3(rs, "RegistryItemCode");
                        newItem.Status = DB.RSField(rs, "Status");

                        // parse the restricted quantities
                        string restrictedQuantitiesValue = DB.RSField(rs, "RestrictedQuantity");
                        if (!restrictedQuantitiesValue.IsNullOrEmptyTrimmed())
                        {
                            string[] quantityValues = restrictedQuantitiesValue.Split(',');
                            if (quantityValues.Length > 0)
                            {
                                foreach (string quantityValue in quantityValues)
                                {
                                    decimal quantity = 0;
                                    if (decimal.TryParse(quantityValue, out quantity))
                                    {
                                        newItem.RestrictedQuantities.Add(quantity);
                                    }
                                }
                            }
                        }
                        else
                        {
                            newItem.RestrictedQuantities = new List<decimal>();
                        }

                        newItem.InStock = DB.RSFieldDecimal(rs, "InStock");
                        newItem.ItemCode = DB.RSField(rs, "ItemCode");
                        newItem.ItemName = DB.RSField(rs, "ItemName");
                        newItem.ItemType = DB.RSField(rs, "ItemType");
                        newItem.KitPricingType = DB.RSField(rs, "KitPricingType");
                        newItem.SupplierCode = DB.RSField(rs, "SupplierCode");
                        newItem.IsDropShip = DB.RSFieldBool(rs, "IsDropShip");
                        newItem.Weight = DB.RSFieldDecimal(rs, "Weight");
                        newItem.m_Notes = DB.RSField(rs, "Notes");
                        newItem.m_MinimumQuantity = Convert.ToInt32(DB.RSFieldDecimal(rs, "MinOrderQuantity"));

                        if (newItem.m_CartType == CartTypeEnum.RecurringCart)
                        {
                            newItem.m_ShippingAddressID = DB.RSField(rs, "ShoppingCartShippingAddressID");
                            newItem.m_ShippingAddressCounter = DB.RSField(rs, "ShippingAddressCounter");
                        }
                        else
                        {
                            newItem.m_ShippingAddressID = DB.RSField(rs, "ShoppingCartShippingAddressID");
                            newItem.m_ShippingAddressCounter = DB.RSFieldInt(rs, "ShippingAddressCounter").ToString();
                        }

                        newItem.IsCheckoutOption = DB.RSFieldBool(rs, "CheckoutOption");

                        m_CartItems.Add(newItem);
                        m_EMail = DB.RSField(rs, "EMail");
                        m_OrderNotes = DB.RSField(rs, "OrderNotes").ToHtmlDecode();
                        newItem.IsCBN = DB.RSFieldBool(rs, "IsCBN");
                        newItem.CBNItemID = DB.RSFieldInt(rs, "CBNItemID");

                        if (newItem.ItemType == Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT)
                        {
                            bool showErrorMessage = HasNoStockPhasedOutComponent(newItem.ItemCode, newItem.Id.ToString());
                            if (showErrorMessage)
                            {
                                newItem.FreeStock = 0;
                                m_HasNoStockPhasedOutItem = true;
                            }
                            else
                            {
                                newItem.FreeStock = 1;
                            }
                        }
                        else if (newItem.IsCBN && !newItem.CBNItemID.IsNullOrEmptyTrimmed())
                        {
                            string cbnUMCode = InterpriseHelper.GetCBNUnitMeasureCode(newItem.ItemCode, newItem.UnitMeasureCode);
                            Interprise.Facade.Base.CBN.CBNTransactionFacade cbnTransactionFacade = new Interprise.Facade.Base.CBN.CBNTransactionFacade(); 
                            decimal freeStock = decimal.Zero;
                            freeStock = cbnTransactionFacade.ConfirmStockCount(newItem.CBNItemID.ToString(), newItem.m_Quantity.ToString(), cbnUMCode);
                            freeStock = (freeStock < 0 ? decimal.Zero : freeStock);
                            newItem.FreeStock = freeStock;  
                        }
                        else
                        {
                            newItem.FreeStock = DB.RSFieldDecimal(rs, "FreeStock");
                        }

                        if (newItem.Status == "P" && newItem.ItemType != Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT)
                        {
                            if (newItem.IsOutOfStock)
                            {
                                m_HasNoStockPhasedOutItem = true;
                            }
                            else if (newItem.IsOverFreeStockCount)
                            {
                                shouldLimitCartToQuantityOnHand = true;
                                isTrimmed = InterpriseHelper.CheckCartInventoryIfTrimmed(m_ThisCustomer, shouldLimitCartToQuantityOnHand);
                                if (isTrimmed)
                                {
                                    m_InventoryTrimmed = isTrimmed;
                                }
                                newItem.m_Quantity = DB.GetSqlNDecimal(String.Format("SELECT Quantity AS N FROM EcommerceShoppingCart WITH (NOLOCK) WHERE ShoppingCartRecID = {0}", DB.SQuote(newItem.m_ShoppingCartRecordID.ToString())));    
                            }                       
                          
                            if (newItem.IsOutOfStock)
                            {
                                m_InventoryTrimmed = false;
                            }
                        }

                        if (shouldLimitCartToQuantityOnHand && m_HasNoStockPhasedOutItem && newItem.Status == "P" && 
                            newItem.ItemType != Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT)
                        {
                            m_InventoryTrimmed = false;
                        }
                        i = i + 1;
                    }
                }
                con.Close();
            }

            if (!couponSet)
            {
                // create an "empty" coupon, but still set the code:
                m_Coupon.m_Code = m_ThisCustomer.CouponCode;
                m_Coupon.m_CouponType = CouponTypeEnum.OrderCoupon;
                m_Coupon.m_Description = string.Empty;
                m_Coupon.m_ExpirationStartDate = System.DateTime.MinValue;
                m_Coupon.m_ExpirationDate = System.DateTime.MinValue;
                m_Coupon.m_DiscountType = CouponDiscountTypeEnum.PercentDiscount; 
                m_Coupon.m_DiscountAmount = System.Decimal.Zero;
                m_Coupon.m_DiscountPercent = 0.0M;
                m_Coupon.m_IncludesFreeShipping = false;
                m_Coupon.m_IncludesAllCustomer  = false;
                m_Coupon.m_IncludesAllProduct = false;
                m_Coupon.m_ExpiresOnFirstUseByAnyCustomer = false;
                m_Coupon.m_ExpiresAfterOneUsageByEachCustomer = false;
                m_Coupon.m_ExpiresAfterNUses = 0;
                m_Coupon.m_RequiresMinimumOrderAmount = System.Decimal.Zero;
                m_Coupon.m_ValidForThisEntity = string.Empty;
                m_Coupon.m_NumUses = 0;
            }
        }

        public CouponStruct GetCoupon()
        {
            return m_Coupon;
        }

        public CartItem.ReserveItemCollection GetReservation(string itemCode)
        {
            //Load reservation information
            //Create a new instance of the reserved transactions collection for the cart item
            var reserveCol = new CartItem.ReserveItemCollection();
            string sql = string.Format("EcommerceGetShoppingCartReservation {0}, {1}", DB.SQuote(ThisCustomer.ContactCode), DB.SQuote(itemCode));

            using (var con = DB.NewSqlConnection())
            {
                con.Open();
                using (var rs = DB.GetRSFormat(con, sql))
                {
                    while (rs.Read())
                    {
                        var reserve = new ReserveItem() 
                        {
                            ItemCode = DB.RSField(rs, "ItemCode"),
                            QtyReserved = DB.RSFieldDecimal(rs, "ReservedQty"),
                            ShipDate = DB.RSFieldDateTime(rs, "DueDate")
                        };
                        reserveCol.Add(reserve);
                    }
                }
                con.Close();
            }
            return reserveCol;
        }

        public void ClearCoupon()
        {
            string customerCode = CommonLogic.IIF(ThisCustomer.IsRegistered, ThisCustomer.CustomerCode, ThisCustomer.CustomerID);
            if (ThisCustomer.IsRegistered)
            {
                DB.ExecuteSQL("UPDATE Customer SET CouponCode=NULL WHERE CustomerCode=" + DB.SQuote(customerCode));
            }
            else
            {
                DB.ExecuteSQL("UPDATE EcommerceCustomer SET CouponCode=NULL WHERE CustomerID=" + DB.SQuote(customerCode));
            }                  
            m_Coupon.m_Code = string.Empty;
            m_Coupon.m_CouponType = CouponTypeEnum.OrderCoupon;
            m_Coupon.m_Description = string.Empty;
            m_Coupon.m_ExpirationStartDate = System.DateTime.MinValue;
            m_Coupon.m_ExpirationDate = System.DateTime.MinValue;
            m_Coupon.m_DiscountType = CouponDiscountTypeEnum.PercentDiscount;
            m_Coupon.m_DiscountAmount = System.Decimal.Zero;
            m_Coupon.m_DiscountPercent = 0.0M;
            m_Coupon.m_IncludesFreeShipping = false;
            m_Coupon.m_IncludesAllCustomer = false;
            m_Coupon.m_IncludesAllProduct = false;
            m_Coupon.m_ExpiresOnFirstUseByAnyCustomer = false;
            m_Coupon.m_ExpiresAfterOneUsageByEachCustomer = false;
            m_Coupon.m_ExpiresAfterNUses = 0;
            m_Coupon.m_RequiresMinimumOrderAmount = System.Decimal.Zero;
            m_Coupon.m_ValidForThisEntity = string.Empty;
            m_Coupon.m_NumUses = 0;
            m_CachedTotals.Clear();
            m_ThisCustomer.CouponCode = string.Empty;
        }

        public string FilterItemAddressList(ArrayList cartItems, string AddressID)
        {
            string result = null; 
            var c = (CartItem)cartItems[0];
            while ((cartItems.Count > 0) && (c.m_ShippingAddressID != AddressID))
            {
                cartItems.Remove(c);
                c = (CartItem)cartItems[0];
            }
            int i = 0;
            do
            {
                c = (CartItem)cartItems[i];
                i++;
            }
            while ((i < cartItems.Count) && (c.m_ShippingAddressID == AddressID));
            if (c.m_ShippingAddressID != AddressID)
            {
                result = c.m_ShippingAddressID;
                i--;
                do
                {
                    c = (CartItem)cartItems[i];
                    cartItems.Remove(c);
                }
                while (i < cartItems.Count);
            }
            else
            {
                result = null;
            }

            return result;
        }

        public string GetLineItemDescription(CartItem c, bool ShowLinkBack, bool VarReadOnly, bool ShowMultiShipAddressUnderItemDescription)
        {
            StringBuilder tmpS = new StringBuilder(4096);

            if (ShowLinkBack)
            {
                tmpS.Append("<a href=\"" + SE.MakeProductLink(c.ItemCounter.ToString(), "") + "\">");
            }
            tmpS.Append("<b>");
            tmpS.Append(AppLogic.MakeProperObjectName(c.ItemName, c.ItemDescription, ThisCustomer.LocaleSetting));
            tmpS.Append("</b>");
            if (ShowLinkBack)
            {
                tmpS.Append("</a>");
            }

            if (c.m_TextOption.Length != 0)
            {
                tmpS.Append("<br>");                
                if (c.m_TextOption.IndexOf("\n") == -1)
                {
                    tmpS.Append(":&nbsp;");
                    tmpS.Append(HttpContext.Current.Server.HtmlDecode(c.m_TextOption));
                }
                else
                {
                    tmpS.Append(":<br>");
                    tmpS.Append(HttpContext.Current.Server.HtmlDecode(c.m_TextOption).Replace("\n", "<br>"));
                }
            }
                        
            if (c.IsAKit)
            {
                tmpS.Append("&nbsp;&nbsp;<a href=\"ShoppingCart_change.aspx?recid=" + c.m_ShoppingCartRecordID.ToString() + "&productid=" + c.ItemCounter.ToString() + "\"><img src=\"" + AppLogic.LocateImageURL("skins/Skin_" + m_SkinID.ToString() + "/images/edit.gif") + "\" align=\"absmiddle\" border=\"0\" alt=\"" + AppLogic.GetString("shoppingcart.cs.4", SkinID, ThisCustomer.LocaleSetting, true) + "\"></a>&nbsp;");

                StringBuilder tmp = new StringBuilder(4096);
                bool first = true;

                using (SqlConnection con = DB.NewSqlConnection())
                {
                    con.Open();
                    using (IDataReader rsx = DB.GetRSFormat(con, "select KitItem.Name, KitCart.Quantity, KitCart.TextOption from EcommerceKitCart with (NOLOCK) inner join KitItem with (NOLOCK) on KitCart.KitItemID=KitItem.KitItemID where ShoppingCartRecID=" + c.m_ShoppingCartRecordID.ToString()))
                    {
                        while (rsx.Read())
                        {
                            if (!first)
                            {
                                tmp.Append("<br>");
                            }
                            tmp.Append("&nbsp;&nbsp;-&nbsp;");
                            if (!AppLogic.AppConfigBool("HideKitQuantity") || DB.RSFieldDecimal(rsx, "Quantity") > 1)
                            {
                                tmp.Append("(");
                                tmp.Append(DB.RSFieldDecimal(rsx, "Quantity").ToString());
                                tmp.Append(") ");
                            }
                            tmp.Append(DB.RSFieldByLocale(rsx, "Name", m_ThisCustomer.LocaleSetting));
                            if (DB.RSField(rsx, "TextOption").Length > 0)
                            {
                                tmpS.Append("&nbsp;");
                                if (DB.RSField(rsx, "TextOption").ToLower().StartsWith("images/orders/image/"))
                                {
                                    tmp.Append(": <a target=\"_blank\" href=\"" + DB.RSField(rsx, "TextOption") + "\">" + AppLogic.GetString("shoppingcart.cs.36", m_SkinID, m_ThisCustomer.LocaleSetting) + "</a>");
                                }
                                else
                                {
                                    tmp.Append(": " + DB.RSField(rsx, "TextOption"));
                                }
                            }
                            first = false;
                        }
                    }
                }

                tmpS.Append("<div style=\"margin-left: 10px;\">");
                tmpS.Append(tmp.ToString());
                tmpS.Append("</div>");
            }
           
            if (c.IsDownload)
            {
                tmpS.Append("<br>");
                tmpS.Append(AppLogic.GetString("shoppingcart.cs.22", m_SkinID, m_ThisCustomer.LocaleSetting));
            }

            if ((this.HasMultipleShippingAddresses()) && ShowMultiShipAddressUnderItemDescription && !c.IsDownload)
            {
                if (!c.IsAKit)
                {
                    tmpS.Append("<br>");
                }
                tmpS.Append(AppLogic.GetString("shoppingcart.cs.24", m_SkinID, m_ThisCustomer.LocaleSetting));
                tmpS.Append(" ");
                if (!Customer.OwnsThisAddress(ThisCustomer.CustomerCode, c.m_ShippingAddressID))
                {
                    tmpS.Append(AppLogic.GetString("checkoutshippingmult.aspx.4", m_SkinID, m_ThisCustomer.LocaleSetting));
                }
                tmpS.Append("<div>");
                tmpS.Append(AppLogic.GetString("order.cs.23", m_SkinID, m_ThisCustomer.LocaleSetting));
                tmpS.Append(c.m_ShippingMethod);
                tmpS.Append("</div>");
            }

            if(CartType == CartTypeEnum.ShoppingCart)
            {
                if (!VarReadOnly)
                {
                    tmpS.Append("<br><br><b>" + AppLogic.GetString("shoppingcart.cs.23", m_SkinID, m_ThisCustomer.LocaleSetting) + "</b><br><textarea class=\"addressselect\" rows=\""  + "\" cols=\""  + "\" name=\"Notes_" + c.m_ShoppingCartRecordID.ToString() + "\" id=\"Notes_" + c.m_ShoppingCartRecordID.ToString() + "\">" + HttpContext.Current.Server.HtmlEncode(c.m_Notes) + "</textarea>");
                }
                else
                {
                    if (c.m_Notes.Length != 0)
                    {
                        tmpS.Append("<br><br><b>" + AppLogic.GetString("shoppingcart.cs.23", m_SkinID, m_ThisCustomer.LocaleSetting) + "</b><br>" + HttpContext.Current.Server.HtmlEncode(c.m_Notes));
                    }
                }
            }
            return tmpS.ToString();
        }

        public string DisplayMultiShipMethodSelector(bool VarReadOnly, Customer ViewingCustomer)
        {
            int ix = 1;
            StringBuilder tmpS = new StringBuilder(4096);
            if (CartType != CartTypeEnum.ShoppingCart)
            {
                return tmpS.ToString(); // can only do this action on the shoppingcart proper, not wish or registry
            }
            if (IsEmpty())
            {
                tmpS.Append("<br><br>");
                if (CartType == CartTypeEnum.ShoppingCart)
                {
                    Topic t1 = new Topic("EmptyCartText", m_ThisCustomer.LocaleSetting, m_SkinID, null);
                    tmpS.Append(t1.Contents);
                }
                if (CartType == CartTypeEnum.WishCart)
                {
                    Topic t1 = new Topic("EmptyWishListText", m_ThisCustomer.LocaleSetting, m_SkinID, null);
                    tmpS.Append(t1.Contents);
                }
                if (CartType == CartTypeEnum.GiftRegistryCart)
                {
                    Topic t1 = new Topic("EmptyGiftRegistryText", m_ThisCustomer.LocaleSetting, m_SkinID, null);
                    tmpS.Append(t1.Contents);
                }
                tmpS.Append("<br><br><br>");
            }
            else
            {
                bool ShowLinkBack = AppLogic.AppConfigBool("LinkToProductPageInCart");
                int ColSpan = 2;

                tmpS.Append("<table width=\"100%\" cellpadding=\"2\" cellspacing=\"0\" border=\"0\">");

                string LastID = string.Empty;
                if (this.HasDownloadComponents())
                {
                    tmpS.Append("<tr>");
                    tmpS.Append("<td height=\"15\" bgcolor=\"#" + AppLogic.AppConfig("LightCellColor") + "\" align=\"left\" valign=\"middle\"><b>");
                    tmpS.Append(string.Format(AppLogic.GetString("shoppingcart.cs.29", m_SkinID, m_ThisCustomer.LocaleSetting), ix.ToString()));
                    ix++;
                    tmpS.Append("</b></td>");
                    tmpS.Append("<td height=\"15\" bgcolor=\"#" + AppLogic.AppConfig("LightCellColor") + "\"  align=\"left\" valign=\"middle\"><b>");
                    tmpS.Append(AppLogic.GetString("shoppingcart.cs.28", m_SkinID, m_ThisCustomer.LocaleSetting));
                    tmpS.Append("</b></td>");
                    tmpS.Append("</tr>");
                    tmpS.Append("<tr><td colspan=\"" + ColSpan.ToString() + "\"><img src=\"images/spacer.gif\" width=\"100%\" height=\"4\"></td></tr>");
                }
                foreach (CartItem c in m_CartItems)
                {
                    bool first = true;
                    if (c.IsDownload)
                    {
                        tmpS.Append("<tr>");

                        // PRODUCT DESCRIPTION COL
                        tmpS.Append("<td align=\"left\" valign=\"top\">");
                        tmpS.Append(GetLineItemDescription(c, ShowLinkBack, VarReadOnly, false));
                        // include Quantity now:
                        tmpS.Append("<br>");
                        tmpS.Append(AppLogic.GetString("shoppingcart.cs.25", m_SkinID, m_ThisCustomer.LocaleSetting));
                        tmpS.Append(": ");
                        tmpS.Append(Localization.ParseLocaleDecimal(c.m_Quantity,m_ThisCustomer.LocaleSetting));
                        tmpS.Append("</td>");

                        // SHIPPING METHOD COL
                        tmpS.Append("<td align=\"left\" valign=\"top\">");
                        if (first)
                        {
                            tmpS.Append(AppLogic.GetString("checkoutshippingmult.aspx.8", SkinID, ThisCustomer.LocaleSetting));
                        }
                        else
                        {
                            tmpS.Append("&nbsp;");
                        }
                        tmpS.Append("</td>");
                        tmpS.Append("</tr>");
                        tmpS.Append("<tr><td colspan=\"" + ColSpan.ToString() + "\"><img src=\"images/spacer.gif\" width=\"100%\" height=\"6\"></td></tr>");
                        first = false;
                    }
                }

                string DistinctAddrIds =GetDistinctShippingAddressIDs(false, false);
                if (DistinctAddrIds.Length != 0)
                {
                    foreach (string AddressID in DistinctAddrIds.Split(','))
                    {
                        string ThisAddressID = AddressID;
                        tmpS.Append("<tr>");
                        tmpS.Append("<td height=\"15\" bgcolor=\"#" + AppLogic.AppConfig("LightCellColor") + "\" align=\"left\" valign=\"middle\"><b>");
                        tmpS.Append(string.Format(AppLogic.GetString("shoppingcart.cs.29", m_SkinID, m_ThisCustomer.LocaleSetting), ix.ToString()));
                        ix++;
                        tmpS.Append("</b></td>");
                        tmpS.Append("<td height=\"15\" bgcolor=\"#" + AppLogic.AppConfig("LightCellColor") + "\" align=\"left\" valign=\"middle\"><b>");
                        tmpS.Append(AppLogic.GetString("shoppingcart.cs.28", m_SkinID, m_ThisCustomer.LocaleSetting));
                        tmpS.Append("</b></td>");
                        tmpS.Append("</tr>");
                        tmpS.Append("<tr><td colspan=\"" + ColSpan.ToString() + "\"><img src=\"images/spacer.gif\" width=\"100%\" height=\"2\"></td></tr>");

                        tmpS.Append("<tr>");

                        // PRODUCT DESCRIPTION COL
                        tmpS.Append("<td align=\"left\" valign=\"top\">");
                        bool FirstItemInThisGroup = true;
                        foreach (CartItem c in m_CartItems)
                        {
                            if (!c.IsDownload && c.m_ShippingAddressID == ThisAddressID)
                            {
                                if (!FirstItemInThisGroup)
                                {
                                    tmpS.Append("<br><br>");
                                }
                                tmpS.Append(GetLineItemDescription(c, ShowLinkBack, VarReadOnly, false));
                                // include Quantity now:
                                tmpS.Append("<br>");
                                tmpS.Append(AppLogic.GetString("shoppingcart.cs.25", m_SkinID, m_ThisCustomer.LocaleSetting));
                                tmpS.Append(": ");
                                tmpS.Append(Localization.ParseLocaleDecimal(c.m_Quantity,m_ThisCustomer.LocaleSetting));
                                FirstItemInThisGroup = false;
                            }
                        }
                        tmpS.Append("</td>");

                        // SHIPING METHOD COL
                        tmpS.Append("<td align=\"left\" valign=\"top\">");
                        Address adr = new Address();
                        adr.LoadByCustomer(ThisCustomer, AddressTypes.Shipping, DistinctAddrIds);
			            tmpS.Append("<b>");
                        tmpS.Append(AppLogic.GetString("shoppingcart.cs.30", m_SkinID, m_ThisCustomer.LocaleSetting));
                        tmpS.Append("</b>");
                        tmpS.Append("<br>");
                        if (m_ThisCustomer.CustomerCode == adr.CustomerCode)
                        {
                            tmpS.Append(adr.DisplayHTML(true));
                        }
                        tmpS.Append("<br><br>");

                        // GET CART TO SHOW SHIPPING METHODS & COSTS FOR ONLY THIS GROUP OF ITEMS BY ADDRESS ID
                        tmpS.Append("<b>");
                        tmpS.Append(AppLogic.GetString("shoppingcart.cs.10", m_SkinID, m_ThisCustomer.LocaleSetting));
                        tmpS.Append("</b>");
                        tmpS.Append("<br>");                        

                        tmpS.Append("</td>");
                        tmpS.Append("</tr>");

                        tmpS.Append("<tr><td colspan=\"" + ColSpan.ToString() + "\"><img src=\"images/spacer.gif\" width=\"100%\" height=\"8\"></td></tr>");
                    }
                }
                tmpS.Append("</table>");
            }
            return tmpS.ToString();
        }

        public string GetDistinctShippingAddressIDs(bool IncludeDownloadItems, bool IncludeSystemItems)
        {
            string tmpS = ",";
            foreach (CartItem c in CartItems)
            {
                if (tmpS.IndexOf("," + c.m_ShippingAddressID.ToString() + ",") == -1)
                {
                    tmpS += c.m_ShippingAddressID.ToString() + ",";
                }
            }
            return tmpS.Trim(',');
        }

        public string GetDistinctShippingAddressCounters(bool IncludeDownloadItems, bool IncludeSystemItems)
        {
            string tmpS = ",";
            foreach (CartItem c in CartItems)
            {
                if (tmpS.IndexOf("," + c.m_ShippingAddressCounter.ToString() + ",") == -1)
                {
                    if ((IncludeDownloadItems == c.IsDownload))
                    {
                        tmpS += c.m_ShippingAddressCounter.ToString() + ",";
                    }
                }
            }
            return tmpS.Trim(',');
        }

        public virtual Guid AddItem(Customer thisCustomer,
                                    string addressCode,
                                    string itemCode,
                                    int itemCounter,
                                    decimal quantity,
                                    string unitMeasureCode,
                                    CartTypeEnum type)
        {
            return AddItem(thisCustomer,
                        addressCode,
                        itemCode,
                        itemCounter,
                        quantity,
                        unitMeasureCode,
                        type, 
                        null);
        }

        public void UpdateUnitMeasureForItem(int cartId, string unitMeasureCode, bool multiShip, bool isRegistryItem = false)
        {
            string updateShoppingCartUnitMeasureCommand = string.Empty;
            if (multiShip || isRegistryItem)
            {
                updateShoppingCartUnitMeasureCommand = string.Format("update EcommerceShoppingCart set UnitMeasureCode = {0} where ShoppingCartRecID={1} and CustomerCode={2}",
                                                                        DB.SQuote(unitMeasureCode),
                                                                        cartId,
                                                                        DB.SQuote(ThisCustomer.CustomerCode));
            }
            else
            {
                updateShoppingCartUnitMeasureCommand = string.Format("update EcommerceShoppingCart set UnitMeasureCode = {0}, ShippingAddressID = {1} where ShoppingCartRecID={2} and CustomerCode={3}",
                                                                        DB.SQuote(unitMeasureCode),
                                                                        DB.SQuote(ThisCustomer.PrimaryShippingAddressID),
                                                                        cartId,
                                                                        DB.SQuote(ThisCustomer.CustomerCode));
            }
            DB.ExecuteSQL(updateShoppingCartUnitMeasureCommand);
        }


        public virtual Guid AddItem(Customer thisCustomer,
                                    string addressCode,
                                    string itemCode,
                                    int itemCounter,
                                    decimal quantity,
                                    string unitMeasureCode,
                                    CartTypeEnum type, 
                                    KitComposition preferredComposition,
                                    CartRegistryParam registryParam = null)
        {
            Guid newCartID = Guid.NewGuid();
            string webSiteCode = InterpriseHelper.ConfigInstance.WebSiteCode;

            string itemType = ProductDA.GetInventoryItemType(itemCode);
            bool isKit = (itemType == Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT);

            if (isKit && null == preferredComposition)
            {
                return Guid.Empty;
            }

            if (Interprise.Framework.Base.Shared.Const.ITEM_TYPE_MATRIX_ITEM == itemType)
            {
                itemCounter = ProductDA.GetInventoryItemCounter(itemCode);
            }

            m_CachedTotals.Clear();
            int RequiresCount = 0;

            // No matching kit is found, but we are in edit mode, just re-compose
            if (isKit && preferredComposition != null && preferredComposition.CartID != Guid.Empty)
            {
                foreach (var currentCartItem in m_CartItems)
                {
                    if (currentCartItem.ItemType != Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT && preferredComposition.CartID != currentCartItem.Id) { continue; }

                    InterpriseHelper.ClearKitItems(ThisCustomer, currentCartItem.ItemCode, currentCartItem.Id);
                    preferredComposition.AddToCart();

                    currentCartItem.SetQuantity(quantity);
                    //currentCartItem.m_Quantity = quantity;

                    this.UpdateUnitMeasureForItem(currentCartItem.m_ShoppingCartRecordID, unitMeasureCode, true);
                    currentCartItem.UnitMeasureCode = unitMeasureCode;

                    return currentCartItem.Id;
                }
            }

            //Anonymous customer 
            //Verify if the anonimous user add to cart again after skip login and continue.
            //All items will be Shipping Address will be assigned to the new address created by the user
            //Since use go back to add to cart again after checkout. Clear the addresss code to allow the cart item to be incremented.
            bool isAnonimousAddToCartAgainAfterSkipSigninAndContinue =
                                ThisCustomer.IsNotRegistered && !ThisCustomer.IsUnregisteredAnonymous &&
                                ThisCustomer.PrimaryShippingAddress != null &&
                                !ThisCustomer.PrimaryShippingAddress.AddressID.IsNullOrEmptyTrimmed();

            if (isAnonimousAddToCartAgainAfterSkipSigninAndContinue) 
            {
                OrderDA.ClearEcommerceCartShippingAddressIDForAnonCustomer(ThisCustomer.CustomerCode, webSiteCode);
                addressCode = String.Empty;
            }

            LoadFromDB(CartType);

            for(int ctr=0; ctr< m_CartItems.Count; ctr++)
            {
                var currentCartItem = m_CartItems[ctr];

                if (itemType == Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT && preferredComposition != null)
                {
                    if (!currentCartItem.Matches(itemCode, addressCode, itemCounter, unitMeasureCode, preferredComposition)) continue;

                    var otherMatchingKitCartItems = new List<CartItem>();
                    for (int ctr2 = ctr+1; ctr2 < m_CartItems.Count; ctr2++)
                    {
                        var otherKitCartItem = m_CartItems[ctr2];
                        if (otherKitCartItem.Matches(itemCode, addressCode, itemCounter, unitMeasureCode, preferredComposition))
                        {
                            otherMatchingKitCartItems.Add(otherKitCartItem);
                        }
                    }

                    currentCartItem.IncrementQuantity(quantity);
                    foreach (var otherMatchingKitcartItem in otherMatchingKitCartItems)
                    {
                        this.RemoveItem(otherMatchingKitcartItem.m_ShoppingCartRecordID);
                    }

                    return currentCartItem.Id;

                }
                else
                {
                    if (!currentCartItem.Matches(itemCode, addressCode, itemCounter, unitMeasureCode)) continue;

                    currentCartItem.IncrementQuantity(quantity);
                    return currentCartItem.Id;
                }               
            }
           

            string sku = String.Empty;
            string description = String.Empty;
            Decimal price = System.Decimal.Zero;
            string dimensions = String.Empty; // formatted as: LxWxH
            Decimal weight = 0.0M;

            string sql = "SELECT A.ItemCode AS SKU, NULL AS SKUSuffix, A.ItemCode AS Name, " +
                "A.ItemCode AS VariantName, B.ItemDescription AS Description, 0.000 AS Price, " +
                "NULL AS SalePrice, C.WeightInPounds AS Weight, C.LengthInInches, C.WidthInInches, C.HeightInInches " +
                "FROM InventoryItem A with (NOLOCK) INNER JOIN InventoryItemDescription B with (NOLOCK) " +
                "ON A.ItemCode = B.ItemCode INNER JOIN InventoryUnitMeasure C with (NOLOCK) " +
                "ON A.ItemCode = C.ItemCode AND C.UnitMeasureCode = " + DB.SQuote(unitMeasureCode) +
                "WHERE LanguageCode = " + DB.SQuote(ThisCustomer.LanguageCode) +
                " AND A.ItemCode= " + DB.SQuote(itemCode);


            using (var con = DB.NewSqlConnection())
            {
                con.Open();
                using (var rs = DB.GetRSFormat(con, sql))
                {
                    if (rs.Read())
                    {
                        sku = AppLogic.MakeProperProductSKU(DB.RSField(rs, "SKU"), DB.RSField(rs, "SKUSuffix"), string.Empty, string.Empty);
                        description = DB.RSFieldByLocale(rs, "Name", m_ThisCustomer.LocaleSetting);
                        if (DB.RSFieldByLocale(rs, "VariantName", m_ThisCustomer.LocaleSetting).Length != 0)
                        {
                            if (DB.RSFieldByLocale(rs, "VariantName", m_ThisCustomer.LocaleSetting) != DB.RSFieldByLocale(rs, "Name", m_ThisCustomer.LocaleSetting))
                            {
                                description += " - " + DB.RSFieldByLocale(rs, "VariantName", m_ThisCustomer.LocaleSetting);
                            }
                            else
                            {
                                description += " - " + CommonLogic.Ellipses(DB.RSFieldByLocale(rs, "Description", m_ThisCustomer.LocaleSetting), 30, true);
                            }
                        }
                        else if (DB.RSFieldByLocale(rs, "Description", m_ThisCustomer.LocaleSetting).Length != 0)
                        {
                            description += " - " + CommonLogic.Ellipses(DB.RSFieldByLocale(rs, "Description", m_ThisCustomer.LocaleSetting), 30, true);
                        }
                        price = DB.RSFieldDecimal(rs, "Price");

                        if (DB.RSFieldDecimal(rs, "SalePrice") != System.Decimal.Zero)
                        {
                            price = DB.RSFieldDecimal(rs, "SalePrice");
                        }
                        weight = DB.RSFieldDecimal(rs, "Weight");
                        decimal length, width, height;
                        length = Convert.ToDecimal(DB.RSFieldDecimal(rs, "LengthInInches"));
                        width = Convert.ToDecimal(DB.RSFieldDecimal(rs, "WidthInInches"));
                        height = Convert.ToDecimal(DB.RSFieldDecimal(rs, "HeightInInches"));

                        if (length != 0 && width != 0 && height != 0)
                        {
                            dimensions = string.Format("{0}x{1}x{2}", length.ToString(), width.ToString(), height.ToString());
                        }

                    }
                }
            }

            if (sku.Length != 0 || AppLogic.AppConfigBool("AllowEmptySkuAddToCart"))
            {
                string tmpSQL = "select 0 as IsTaxable, 0 as IsShipSeparately, CASE WHEN ItemType = 'Electronic Download' THEN 1 ELSE 0 END AS IsDownload,";
                tmpSQL += "0 as FreeShipping, 1 as RecurringInterval, 3 as RecurringIntervalType, null as DownloadLocation, ";
                tmpSQL += "CASE WHEN ItemType = 'Service' THEN 1 ELSE 0 END AS IsSystem, 0 as IsAKit, 0 as IsAPack from InventoryItem with (NOLOCK) where counter=" + itemCounter.ToString();

                using (var con = DB.NewSqlConnection())
                {
                    con.Open();
                    using (var rst = DB.GetRSFormat(con, tmpSQL))
                    {
                        if (rst.Read())
                        {
                            int isTaxable = CommonLogic.IIF(DB.RSFieldBool(rst, "IsTaxable"), 1, 0);
                            int isShipSeparately = CommonLogic.IIF(DB.RSFieldBool(rst, "IsShipSeparately"), 1, 0);
                            int isDownload = CommonLogic.IIF(DB.RSFieldBool(rst, "IsDownload"), 1, 0);
                            int FreeShipping = CommonLogic.IIF(DB.RSFieldBool(rst, "FreeShipping"), 1, 0);
                            string downloadLocation = DB.RSField(rst, "DownloadLocation");
                            int RecurringInterval = DB.RSFieldInt(rst, "RecurringInterval");
                            int IsSystem = CommonLogic.IIF(DB.RSFieldBool(rst, "IsSystem"), 1, 0);
                            int IsAKit = CommonLogic.IIF(DB.RSFieldBool(rst, "IsAKit"), 1, 0);
                            int IsAPack = CommonLogic.IIF(DB.RSFieldBool(rst, "IsAPack"), 1, 0);
                            if (RecurringInterval == 0)
                            {
                                RecurringInterval = 1; // for backwards compatability
                            }
                            var RecurringIntervalType = (DateIntervalTypeEnum)DB.RSFieldInt(rst, "RecurringIntervalType");
                            if (RecurringIntervalType == DateIntervalTypeEnum.Unknown)
                            {
                                RecurringIntervalType = DateIntervalTypeEnum.Monthly; // for backwards compatibility
                            }

                            // added the id to be used when adding kit items...
                            string NewGUID = newCartID.ToString();

                            StringBuilder sql2 = null;

                            if (registryParam != null)
                            {
                                GiftRegistryID = registryParam.RegistryID;
                                GiftRegistryItemCode = registryParam.RegistryItemCode;
                            }

                            bool isUseGiftRegistry = (registryParam != null && registryParam.RegistryID.HasValue && registryParam.RegistryItemCode.HasValue && AppLogic.AppConfigBool("GiftRegistry.Enabled"));

                            sql2 = new StringBuilder("insert into EcommerceShoppingCart(CartType,ShoppingCartRecGUID,CustomerCode,ShippingAddressID,ItemCode, ProductID,SubscriptionInterval,SubscriptionIntervalType,VariantID,ProductSKU,ProductPrice,CustomerEntersPrice,ProductWeight,ProductDimensions,Quantity,RequiresCount,ChosenColor,ChosenColorSKUModifier,ChosenSize,ChosenSizeSKUModifier,TextOption,IsTaxable,IsDownload,DownloadLocation,FreeShipping,RecurringInterval,RecurringIntervalType, IsSystem, IsAKit, IsAPack, UnitMeasureCode, WebsiteCode, KitPricingType,ContactCode) values(", 10000);
                            if (isUseGiftRegistry)
                            {
                                sql2 = new StringBuilder("insert into EcommerceShoppingCart(CartType,ShoppingCartRecGUID,CustomerCode,ShippingAddressID,ItemCode, ProductID,SubscriptionInterval,SubscriptionIntervalType,VariantID,ProductSKU,ProductPrice,CustomerEntersPrice,ProductWeight,ProductDimensions,Quantity,RequiresCount,ChosenColor,ChosenColorSKUModifier,ChosenSize,ChosenSizeSKUModifier,TextOption,IsTaxable,IsDownload,DownloadLocation,FreeShipping,RecurringInterval,RecurringIntervalType, IsSystem, IsAKit, IsAPack, UnitMeasureCode, WebsiteCode, KitPricingType,ContactCode, GiftRegistryID, RegistryItemCode) values(", 10000);
                            }

                            sql2.Append(((int)CartType).ToString() + ",");
                            sql2.Append(DB.SQuote(NewGUID) + ",");

                            sql2.Append(DB.SQuote(m_ThisCustomer.CustomerCode.ToString()) + ",");

                            if (addressCode.ToString().Length > 0)
                            {
                                sql2.Append(DB.SQuote(addressCode.ToString()) + ",");
                            }
                            else
                            {
                                sql2.Append("null,");
                            }

                            sql2.Append(DB.SQuote(itemCode) + ",");
                            sql2.Append(itemCounter.ToString() + ",");

                            int IntVal = 0;
                            DateIntervalTypeEnum IntValType = DateIntervalTypeEnum.Monthly;
                            sql2.Append(IntVal.ToString() + ",");
                            sql2.Append(((int)IntValType).ToString() + ",");

                            sql2.Append(itemCounter.ToString() + ",");
                            sql2.Append(DB.SQuote(sku) + ",");

                            sql2.Append(Localization.CurrencyStringForDBWithoutExchangeRate(Convert.ToDecimal("0")) + ",");

                            sql2.Append("0,");
                            sql2.Append(Localization.DecimalStringForDB(weight) + ",");
                            sql2.Append(DB.SQuote(dimensions) + ",");
                            sql2.Append(quantity.ToString() + ",");
                            sql2.Append(RequiresCount.ToString() + ",");
                            sql2.Append(DB.SQuote(string.Empty) + ",");
                            sql2.Append(DB.SQuote(string.Empty) + ",");
                            sql2.Append(DB.SQuote(string.Empty) + ",");
                            sql2.Append(DB.SQuote(string.Empty) + ",");
                            sql2.Append(DB.SQuote(string.Empty) + ",");
                            sql2.Append(isTaxable.ToString() + ",");                            
                            sql2.Append(isDownload.ToString() + ",");
                            sql2.Append(DB.SQuote(downloadLocation) + ",");
                            sql2.Append(FreeShipping.ToString() + ",");
                            sql2.Append(RecurringInterval.ToString() + ",");
                            sql2.Append(((int)RecurringIntervalType).ToString() + ",");
                            sql2.Append(IsSystem.ToString() + ",");
                            sql2.Append(IsAKit.ToString() + ",");
                            sql2.Append(IsAPack.ToString() + ",");

                            // Unit Measure Code
                            sql2.Append(DB.SQuote(unitMeasureCode) + ",");

                            // WebSite Code
                            sql2.Append(DB.SQuote(webSiteCode) + ",");

                            if (itemType == Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT &&
                                null != preferredComposition)
                            {
                                sql2.Append(DB.SQuote(preferredComposition.PricingType) + ",");
                            }
                            else
                            {
                                sql2.Append("'', ");
                            }

                            sql2.Append(DB.SQuote(thisCustomer.ContactCode));

                            if (isUseGiftRegistry)
                            {
                                sql2.Append(",");
                                sql2.Append(DB.SQuote(registryParam.RegistryID.Value.ToString()));
                                sql2.Append(",");
                                sql2.Append(DB.SQuote(registryParam.RegistryItemCode.Value.ToString()));
                            }

                            sql2.Append(")");
                            DB.ExecuteSQL(sql2.ToString());
                        }
                    }
                }

                if (itemType == Interprise.Framework.Base.Shared.Const.ITEM_TYPE_KIT)
                {
                    preferredComposition.CartID = newCartID;
                    preferredComposition.AddToCart();
                }
            }

            return newCartID;
        }

        public virtual void SetItemQuantity(int cartRecordID, decimal Quantity)
        {
            m_CachedTotals.Clear();
            Quantity = CommonLogic.RoundQuantity(Quantity);
            if (Quantity == 0)
            {
                RemoveItem(cartRecordID);
            }
            else
            {
                string sql = "UPDATE EcommerceShoppingCart SET Quantity=" + Localization.ParseDBDecimal(Quantity) + " WHERE ShoppingCartRecID=" + 
                                cartRecordID.ToString() + " AND CustomerCode=" + DB.SQuote(m_ThisCustomer.CustomerCode.ToString()) + " and ContactCode=" + 
                                DB.SQuote(m_ThisCustomer.ContactCode.ToString());
                DB.ExecuteSQL(sql);
                for (int i = 0; i < m_CartItems.Count; i++)
                {
                    if (((CartItem)m_CartItems[i]).m_ShoppingCartRecordID == cartRecordID)
                    {
                        CartItem ci = (CartItem)m_CartItems[i];
                        ci.m_Quantity = Quantity;
                        m_CartItems[i] = ci;
                        break;
                    }
                }
            }
            return;
        }

        public void ShipAllItemsToThisAddress(Address shippingAddress)
        {
            //Exclude the updating of addressid if registry item
            this.CartItems.Where(item => !item.GiftRegistryID.HasValue)
                          .AsParallel()
                          .ForEach(itm => {
                             SetItemAddress(itm.m_ShoppingCartRecordID, shippingAddress.AddressID);
                          });
        }

        public void SetItemAddress(int cartRecordID, string AddressID)
        {
            m_CachedTotals.Clear();
            string sql = string.Format("UPDATE EcommerceShoppingCart SET ShippingAddressID= {0}, ContactCode = {1} WHERE ShoppingCartRecID= {2} AND CustomerCode= {3}", DB.SQuote(AddressID), DB.SQuote(ThisCustomer.ContactCode), cartRecordID.ToString(), DB.SQuote(m_ThisCustomer.CustomerCode));
            DB.ExecuteSQL(sql);
            return;
        }

        public void SetItemShippingMethodID(int cartRecordID, string ShippingMethodID)
        {
            m_CachedTotals.Clear();
            string sql = "update WeShoppingCart set ShippingMethodID=" + ShippingMethodID.ToString() + " where ShoppingCartRecID=" + cartRecordID.ToString() + " and CustomerID=" + m_ThisCustomer.CustomerCode.ToString();
            DB.ExecuteSQL(sql);
            return;
        }

        public void RemoveItem(int cartRecordID)
        {
            m_CachedTotals.Clear();
            if (cartRecordID != 0)
            {
                string itemCode = string.Empty;
                decimal Quantity = 0;
                int RequiresCount = 0;
                string RequiresProducts = string.Empty;
                CartTypeEnum CartType = CartTypeEnum.ShoppingCart;

                using (var con = DB.NewSqlConnection())
                {
                    con.Open();
                    using (var rs = DB.GetRSFormat(con, "Select ItemCode, ProductID, VariantID, Quantity, RequiresCount, CartType from EcommerceShoppingCart  with (NOLOCK) where ShoppingCartRecID={0}", cartRecordID))
                    {
                        if (rs.Read())
                        {
                            itemCode = DB.RSField(rs, "ItemCode");
                            Quantity = DB.RSFieldDecimal(rs, "Quantity");
                            RequiresCount = DB.RSFieldInt(rs, "RequiresCount");
                            CartType = (CartTypeEnum)DB.RSFieldInt(rs, "CartType");
                        }
                    }
                }

                string sql = string.Format("delete from EcommerceShoppingCart where ShoppingCartRecID={0} and CustomerCode={1} and ContactCode={2}", cartRecordID, DB.SQuote(m_ThisCustomer.CustomerCode), DB.SQuote(m_ThisCustomer.ContactCode));
                DB.ExecuteSQL(sql);
                for (int i = 0; i < m_CartItems.Count; i++)
                {
                    if (((CartItem)m_CartItems[i]).m_ShoppingCartRecordID == cartRecordID)
                    {
                        m_CartItems.RemoveAt(i);
                        break;
                    }
                }

                //remove reserve qty from specific item
                sql = string.Format("DELETE FROM EcommerceShoppingCartReservation WHERE ContactCode = {0} and ItemCode={1}",  DB.SQuote(m_ThisCustomer.ContactCode), DB.SQuote(itemCode));
                DB.ExecuteSQL(sql);

                //remove all order options if those are the only items left in the cart
                bool blnRemoveAllOrderOptions = true;
                foreach (CartItem item in m_CartItems)
                {
                    if (!item.IsCheckoutOption)
                    {
                        //found at least one 'real' item, so set the flag and quit
                        blnRemoveAllOrderOptions = false;
                        break;
                    }
                }

                if (blnRemoveAllOrderOptions && CartType != CartTypeEnum.WishCart)
                {
                    //the only items in the cart are order options, so delete everything
                    string strRemoveOrderOptions = string.Format("DELETE FROM EcommerceShoppingCart WHERE CustomerCode = {0} AND ContactCode = {1} AND CartType = {2}", DB.SQuote(m_ThisCustomer.CustomerCode), DB.SQuote(m_ThisCustomer.ContactCode), (int)CartType);
                    DB.ExecuteSQL(strRemoveOrderOptions);
                    m_CartItems.Clear();

                    //remove all reserved
                    sql = string.Format("DELETE FROM EcommerceShoppingCartReservation WHERE ContactCode = {0}", DB.SQuote(m_ThisCustomer.ContactCode));
                    DB.ExecuteSQL(sql);
                }
            }
            return;
        }

        public bool IsEmpty()
        {
            return (m_CartItems.Count == 0);
        }

        public void ClearContents()
        {
            m_CachedTotals.Clear();
            m_CartItems.Clear();
            //DB.ExecuteSQL("delete from EcommerceKitCart where CartType=" + ((int)m_CartType).ToString() + " and (ShoppingCartRecID=0 or ShoppingCartRecID in (select ShoppingCartRecID from EcommerceShoppingCart with (NOLOCK) where CustomerID=" + m_ThisCustomer.CustomerCode.ToString() + " and CartType=" + ((int)m_CartType).ToString() + " and ContactCode=" + DB.SQuote(m_ThisCustomer.ContactCode.ToString()) + "))");
            //DB.ExecuteSQL("delete from EcommerceShoppingCart where CustomerID=" + m_ThisCustomer.CustomerCode.ToString() + " and CartType=" + ((int)m_CartType).ToString() + " and ContactCode=" + DB.SQuote(m_ThisCustomer.ContactCode.ToString()));
            DB.ExecuteSQL(string.Format("DELETE FROM EcommerceKitCart WHERE CartID IN (SELECT ShoppingCartRecGUID FROM EcommerceShoppingCart WHERE CartType={0} AND WebSiteCode={1} AND ContactCode={2} AND CustomerCode={3})", ((int)m_CartType).ToString(), DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode), DB.SQuote(m_ThisCustomer.ContactCode), DB.SQuote(m_ThisCustomer.CustomerCode)));
            DB.ExecuteSQL(string.Format("DELETE FROM EcommerceShoppingCart WHERE CartType={0} AND WebSiteCode={1} AND ContactCode={2} AND CustomerCode={3}", ((int)m_CartType).ToString(), DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode), DB.SQuote(m_ThisCustomer.ContactCode), DB.SQuote(m_ThisCustomer.CustomerCode)));
        }

        public virtual bool HasCoupon()
        {
            throw new NotSupportedException("Use InterpriseShopping Cart's override for the implementation");
        }

        // returns true if this cart has any items which are download items:
        public bool HasDownloadComponents()
        {
            foreach (CartItem c in m_CartItems)
            {
                if (c.IsDownload)
                {
                    return true;
                }
            }
            return false;
        }

        // returns true if this cart has any items which are service items:
        public bool HasServiceComponents()
        {
            foreach (CartItem c in m_CartItems)
            {
                if (c.IsService)
                {
                    return true;
                }
            }
            return false;
        }

        // returns true if this cart has any items which are download goods:
        public bool HasSupplierDropShipComponents() 
        {
            foreach (CartItem c in m_CartItems)
            {
                if (c.IsDropShip && !CommonLogic.IsStringNullOrEmpty(c.SupplierCode))
                {
                    return true;
                }
            }
            return false;
        }

        // returns true if this order has ONLY download and service items:
        public bool IsNoShippingRequired()
        {
            foreach (CartItem c in m_CartItems)
            {
                if (!c.IsDownload && c.ItemType != Interprise.Framework.Base.Shared.Const.ITEM_TYPE_SERVICE)
                {
                    return false;
                }
            }
            return true;
        }

        public int NumAtThisShippingAddress(string ShippingAddressID)
        {
            int i = 0;
            foreach (CartItem c in m_CartItems)
            {
                if (c.m_ShippingAddressID == ShippingAddressID)
                {
                    i++;
                }
            }
            return i;
        }

        public bool IsAllDefaultShippingAddressItems()
        {
            foreach (CartItem c in m_CartItems)
            {
                if (!(c.m_ShippingAddressID == string.Empty || c.m_ShippingAddressID == ThisCustomer.PrimaryShippingAddressID))
                {
                    return false;
                }
            }
            return true;
        }

        public CartItem FirstItem()
        {
            // don't call this on an empty cart, or you will get an exception (duh)
            return ((CartItem)CartItems[0]);
        }

        public string FirstItemShippingAddressID()
        {
            string ID = string.Empty;
            try
            {
                ID = FirstItem().m_ShippingAddressID;
            }
            catch
            { }
            return ID;
        }

        public bool HasPrimaryShippingAddressItems()
        {
            foreach (CartItem c in m_CartItems)
            {
                if (c.m_ShippingAddressID == ThisCustomer.PrimaryShippingAddressID)
                {
                    return true;
                }
            }
            return false;
        }

        public decimal NumItems()
        {
            decimal tmp = 0;
            if (m_CartItems.Count() > 0)
            {
                tmp = m_CartItems.Sum(item => item.m_Quantity);                                                
            }
            return tmp;
        }

        public bool HasNonPrimaryShippingAddressItems()
        {
            foreach (CartItem c in m_CartItems)
            {
                if (c.m_ShippingAddressID != ThisCustomer.PrimaryShippingAddressID)
                {
                    return true;
                }
            }
            return false;
        }

        public bool HasMultipleShippingAddresses()
        {
            string LastAddressID = string.Empty;
            bool first = true;
            foreach (CartItem c in m_CartItems)
            {
                if (first)
                {
                    LastAddressID = c.m_ShippingAddressID;
                }
                else
                {
                    if (c.m_ShippingAddressID != LastAddressID)
                    {
                        return true;
                    }
                }
                first = false;
            }
            return false;
        }  

        // NOT updated for multi-ship or gift registry (yet)
        public static string DisplayMiniCart(System.Collections.Generic.Dictionary<string, EntityHelper> EntityHelpers, Customer ThisCustomer, int m_SkinID, bool IncludeFrame)
        {
            string ImgFilename = string.Empty;
            bool existing = false;
            bool exists = false;

            InterpriseIntegration.InterpriseShoppingCart cart = new  InterpriseIntegration.InterpriseShoppingCart(EntityHelpers, m_SkinID, ThisCustomer, CartTypeEnum.ShoppingCart, string.Empty, false, true);
            if (cart.IsEmpty())
            {
                return string.Empty;
            }

            StringBuilder tmpS = new StringBuilder(10000);

            if (IncludeFrame)
            {
                tmpS.Append("<table width=\"150\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"border-style: solid; border-width: 0px; border-color: #" + AppLogic.AppConfig("HeaderBGColor") + "\">\n");
                tmpS.Append("<tr><td align=\"left\" valign=\"top\">\n");
                tmpS.Append("<img src=\"" + AppLogic.LocateImageURL("skins/Skin_" + m_SkinID.ToString() + "/images/minicart.gif") + "\" border=\"0\"><br>");
                tmpS.Append("<table width=\"190\" cellpadding=\"4\" cellspacing=\"0\" border=\"0\" style=\"" + AppLogic.AppConfig("BoxFrameStyle") + "\">\n");
                tmpS.Append("<tr><td align=\"center\" valign=\"top\">\n");
            }

            bool ShowLinkBack = AppLogic.AppConfigBool("LinkToProductPageInCart");
            foreach (CartItem c in cart.m_CartItems)
            {
                if (ShowLinkBack)
                {
                    switch (c.ItemType)
                    {
                        case Interprise.Framework.Base.Shared.Const.ITEM_TYPE_MATRIX_GROUP:
                        case Interprise.Framework.Base.Shared.Const.ITEM_TYPE_MATRIX_ITEM:
                            using (SqlConnection con = DB.NewSqlConnection())
                            {
                                con.Open();
                                using (IDataReader reader = DB.GetRSFormat(con, string.Format("SELECT ItemCode FROM InventoryMatrixItem with (NOLOCK) WHERE MatrixItemCode = {0}", DB.SQuote(c.ItemCode))))
                                {
                                    if (reader.Read())
                                    {
                                        tmpS.Append("<a href=\"" + InterpriseHelper.MakeItemLink(DB.RSField(reader, "ItemCode")) + "\">");
                                    }
                                }
                            }
                            break;
                        default:
                            tmpS.Append("<a href=\"" + InterpriseHelper.MakeItemLink(c.ItemCode) + "\">");
                            break;
                    }
                }
                if (AppLogic.AppConfigBool("ShowPicsInMiniCart"))
                {
                    string ProdPic = string.Empty;
                    ImgFilename = AppLogic.NoPictureImageURL(true, ThisCustomer.SkinID, ThisCustomer.LocaleSetting);
                    using (SqlConnection con = DB.NewSqlConnection())
                    {
                        con.Open();
                        using (IDataReader reader = DB.GetRSFormat(con, "SELECT Filename FROM InventoryOverrideImage with (NOLOCK) WHERE ItemCode = {0} AND WebSiteCode = {1} AND IsDefaultIcon = 1", DB.SQuote(c.ItemCode), DB.SQuote(InterpriseHelper.ConfigInstance.WebSiteCode)))
                        {
                            existing = reader.Read();
                            if (existing)
                            {
                                ImgFilename = (DB.RSField(reader, "Filename"));
                            }
                        }
                    }

                    //use filename instead of product counter. will be applicable on 5.5.1 onwards                        
                    ProdPic = AppLogic.LocateImageFilenameUrl("Product", c.ItemCode.ToString(), "icon", ImgFilename, AppLogic.AppConfigBool("Watermark.Enabled"), out exists);


                    int MaxWidth = AppLogic.AppConfigNativeInt("MiniCartMaxIconWidth");
                    if (MaxWidth == 0)
                    {
                        MaxWidth = 125;
                    }
                    int MaxHeight = AppLogic.AppConfigNativeInt("MiniCartMaxIconHeight");
                    if (MaxHeight == 0)
                    {
                        MaxHeight = 125;
                    }
                    if (ProdPic.Length != 0)
                    {
                        //Additional img prooerties...
                        string seTitle = "";
                        string seAltText = "";
                        AppLogic.GetSEImageAttributes(c.ItemCode.ToString(), "ICON", AppLogic.GetLanguageCode(ThisCustomer.LocaleSetting), ref seTitle, ref seAltText);

                        System.Drawing.Size size = CommonLogic.GetImagePixelSize(ProdPic);
                        if (size.Width > MaxWidth)
                        {
                            tmpS.Append("<img align=\"center\" src=\"" + ProdPic + "\" width=\"" + MaxWidth.ToString() + "\" border=\"0\" alt=\"" + seAltText + "\" title=\"" + seTitle + "\"><br>");
                        }
                        else if (size.Height > MaxHeight)
                        {
                            tmpS.Append("<img align=\"center\" src=\"" + ProdPic + "\" height=\"" + MaxHeight + "\" border=\"0\" alt=\"" + seAltText + "\" title=\"" + seTitle + "\"><br>");
                        }
                        else
                        {
                            tmpS.Append("<img align=\"center\" src=\"" + ProdPic + "\" border=\"0\" alt=\"" + seAltText + "\" title=\"" + seTitle + "\"><br>");
                        }
                    }
                }

                tmpS.Append(HttpUtility.HtmlEncode(c.DisplayName));
                if (ShowLinkBack)
                {
                    tmpS.Append("</a>");
                }
                tmpS.Append("<br>");

                tmpS.Append("Qty " + Localization.ParseLocaleDecimal(c.m_Quantity,ThisCustomer.LocaleSetting) + "&nbsp;" + InterpriseHelper.FormatCurrencyForCustomer(c.Price, ThisCustomer.CurrencyCode)); //.CurrencyString(PR));
                if (AppLogic.AppConfigBool("VAT.Enabled"))
                {
                    if (ThisCustomer.VATSettingReconciled == VatDefaultSetting.Inclusive)
                    {
                        tmpS.Append(" <span class=\"VATLabel\">" + AppLogic.GetString("showproduct.aspx.38", m_SkinID, ThisCustomer.LocaleSetting) + "</span>\n");
                    }
                    else
                    {
                        tmpS.Append(" <span class=\"VATLabel\">" + AppLogic.GetString("showproduct.aspx.37", m_SkinID, ThisCustomer.LocaleSetting) + "</span>\n");
                    }
                }
                tmpS.Append("<br/><br/>");
            }

            tmpS.Append(AppLogic.GetString("shoppingcart.cs.26", m_SkinID, ThisCustomer.LocaleSetting) + " " +
                InterpriseHelper.FormatCurrencyForCustomer(cart.GetCartSubTotal(), ThisCustomer.CurrencyCode) +
                "<br/><br/>");

            tmpS.Append("<a href=\"ShoppingCart.aspx\"><font color=\"BLUE\"><b>" + AppLogic.GetString("shoppingcart.cs.21", m_SkinID, ThisCustomer.LocaleSetting) + "</b></font></a>");

            if (IncludeFrame)
            {
                tmpS.Append("</td></tr>\n");
                tmpS.Append("</table>\n");
                tmpS.Append("</td></tr>\n");
                tmpS.Append("</table>\n");
            }

            return tmpS.ToString();
        }

        public CartTypeEnum CartType
        {
            get
            {
                return m_CartType;
            }
            set
            {
                m_CartType = value;
            }
        }

        public bool ShippingIsFree
        {
            get
            {
                return m_ShippingIsFree;
            }
            set
            {
                m_ShippingIsFree = value;
            }
        }

        public bool CouponsAllowed
        {
            get
            {
                return m_CouponsAllowed;
            }
            set
            {
                m_CouponsAllowed = value;
            }
        }

        public bool CartAllowsShippingMethodSelection
        {
            get
            {
                return !this.IsNoShippingRequired();
            }
        }

        public string OrderNotes
        {
            get
            {
                return m_OrderNotes;
            }
        }

        public System.Collections.Generic.Dictionary<string, EntityHelper> EntityHelpers
        {
            get
            {
                return m_EntityHelpers;
            }
        }

        public bool InventoryTrimmed
        {
            get
            {
                return m_InventoryTrimmed;
            }
        }

        public bool HasNoStockPhasedOutItem
        {
            get
            {
                return m_HasNoStockPhasedOutItem;
            }
        }

        public bool MinimumQuantitiesUpdated
        {
            get
            {
                return m_MinimumQuantitiesUpdated;
            }
        }

        public decimal FreeShippingThreshold
        {
            get
            {
                return m_FreeShippingThreshold;
            }
        }

        public decimal MoreNeededToReachFreeShipping
        {
            get
            {
                return m_MoreNeededToReachFreeShipping;
            }
        }

        public string EMail
        {
            get
            {
                return m_EMail;
            }
        }

        public CartItemCollection CartItems
        {
            get
            {
                return m_CartItems;
            }
            set
            {
                m_CartItems = value;
            }
        }

        public Customer ThisCustomer
        {
            get
            {
                return m_ThisCustomer;
            }
        }

        public int SkinID
        {
            get
            {
                return m_SkinID;
            }
        }

        public string OriginalRecurringOrderNumber
        {
            get
            {
                return m_OriginalRecurringOrderNumber;
            }
        }

        public CouponStruct Coupon
        {
            get
            {
                return m_Coupon;
            }
            set
            {
                m_Coupon = value;
            }
        }

        public int IsShipSeparatelyCount()
        {
            int ret = 0;
            foreach (CartItem item in m_CartItems)
            {
                if (item.CanShipSeparately)
                    ret++;
            }
            return ret;
        }

        public bool HasRegistryItems()
        { 
            if(m_CartItems == null || m_CartItems.Count() == 0) return false;
            return (m_CartItems.Any(itm => itm.GiftRegistryID.HasValue));
        }
    
    }

    public class StockByUnitMeasure 
    {
        public string unitMeasureCode;
        public decimal unitMeasureQuantity;
        public decimal inStock;
        public decimal freeStock;
    }
}















